// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: Apache-2.0

package resource_exam_api_serv

import (
	"context"
	"time"

	"gitcode.com/lvupclub/lvup-api/dao"
	"gitcode.com/lvupclub/lvup-api/dao/resource_dao"
	"gitcode.com/lvupclub/lvup-api/dao/roadmap_dao"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_exam_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_exam_type_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_data_type_api"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
)

func (apiImpl *ResourceExamApiImpl) ListByRoadmap(ctx context.Context, req *resource_exam_api.ListByRoadmapRequest) (*resource_exam_api.ListByRoadmapResponse, error) {
	emptyAny, err := anypb.New(&resource_exam_type_api.EmptyAnswer{})
	if err != nil {
		return nil, err
	}

	emptyList := []*resource_exam_api.QuestionInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &resource_exam_api.ListByRoadmapResponse{
			Code:         resource_exam_api.ListByRoadmapResponse_CODE_WRONG_SESSION,
			ErrMsg:       "会话不存在",
			QuestionList: emptyList,
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &resource_exam_api.ListByRoadmapResponse{
			Code:         resource_exam_api.ListByRoadmapResponse_CODE_NO_ROADMAP,
			ErrMsg:       "成长路线图不存在",
			QuestionList: emptyList,
		}, nil
	}
	allowAccess := apiImpl.checkAccessRoadmapNode(ctx, roadmapItem, sessItem, req.TargetMemberUserId)
	if !allowAccess {
		return &resource_exam_api.ListByRoadmapResponse{
			Code:         resource_exam_api.ListByRoadmapResponse_CODE_NO_PERMISSION,
			ErrMsg:       "没有权限",
			QuestionList: emptyList,
		}, nil
	}
	resourceId, valid := apiImpl.validNodeData(ctx, req.RoadmapId, req.NodeId)
	if !valid {
		return &resource_exam_api.ListByRoadmapResponse{
			Code:         resource_exam_api.ListByRoadmapResponse_CODE_NO_RESOURCE,
			ErrMsg:       "资料库不存在",
			QuestionList: emptyList,
		}, nil
	}

	stateItemList, err := resource_dao.QuestionStateDao.List(ctx, req.TargetMemberUserId, resourceId)
	if err != nil {
		return nil, err
	}
	stateMap := map[string]*resource_dao.QuestionStateItem{}
	for _, stateItem := range stateItemList {
		stateMap[stateItem.QuestionId] = stateItem
	}

	questionItemList, err := resource_dao.QuestionInfoDao.List(ctx, resourceId)
	if err != nil {
		return nil, err
	}

	//生成结果
	questionList := []*resource_exam_api.QuestionInfo{}
	for _, questionItem := range questionItemList {
		question, err := questionItem.ToQuestionInfo()
		if err != nil {
			continue
		}
		state, ok := stateMap[questionItem.QuestionId]
		if ok {
			answer := &anypb.Any{}
			err = proto.Unmarshal(state.AnswerData, answer)
			if err != nil {
				continue
			}
			question.Answer = answer
			question.AnswerTime = state.AnswerTime
		} else {
			question.Answer = emptyAny
		}
		questionList = append(questionList, question)
	}

	return &resource_exam_api.ListByRoadmapResponse{
		Code:         resource_exam_api.ListByRoadmapResponse_CODE_OK,
		QuestionList: questionList,
	}, nil
}

func (apiImpl *ResourceExamApiImpl) checkAccessRoadmapNode(ctx context.Context, roadmapItem *roadmap_dao.RoadmapInfoDbItem, sessItem *dao.SessionDbItem, targetUserId string) bool {
	if roadmapItem.OwnerUserId == sessItem.UserId {
		if sessItem.UserId != targetUserId {
			exist, err := roadmap_dao.RoadmapMemberDao.Exist(ctx, roadmapItem.RoadmapId, targetUserId)
			if err != nil {
				return false
			}
			if !exist {
				return false
			}
		}
	} else {
		if sessItem.UserId != targetUserId {
			return false
		}
		exist, err := roadmap_dao.RoadmapMemberDao.Exist(ctx, roadmapItem.RoadmapId, targetUserId)
		if err != nil {
			return false
		}
		if !exist {
			return false
		}
	}
	return true
}

func (apiImpl *ResourceExamApiImpl) validNodeData(ctx context.Context, roadmapId, nodeId string) (string, bool) {
	nodeItem, err := roadmap_dao.NodeInfoDao.Get(ctx, roadmapId, nodeId)
	if err != nil {
		return "", false
	}

	nodeContent := &anypb.Any{}
	err = proto.Unmarshal(nodeItem.ContentData, nodeContent)
	if err != nil {
		return "", false
	}
	innerResourceData := &roadmap_data_type_api.InnerResourceData{}
	err = nodeContent.UnmarshalTo(innerResourceData)
	if err != nil {
		return "", false
	}
	return innerResourceData.ResourceId, innerResourceData.ResourceType == uint32(resource_api.RESOURCE_TYPE_RESOURCE_TYPE_EXAM)
}

func (apiImpl *ResourceExamApiImpl) GetByRoadmap(ctx context.Context, req *resource_exam_api.GetByRoadmapRequest) (*resource_exam_api.GetByRoadmapResponse, error) {
	emptyAny, err := anypb.New(&resource_exam_type_api.EmptyAnswer{})
	if err != nil {
		return nil, err
	}

	emptyInfo := &resource_exam_api.QuestionInfo{
		BasicInfo: &resource_exam_api.BasicQuestionInfo{
			Question: emptyAny,
		},
		Answer: emptyAny,
	}
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &resource_exam_api.GetByRoadmapResponse{
			Code:     resource_exam_api.GetByRoadmapResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			Question: emptyInfo,
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &resource_exam_api.GetByRoadmapResponse{
			Code:     resource_exam_api.GetByRoadmapResponse_CODE_NO_ROADMAP,
			ErrMsg:   "成长路线图不存在",
			Question: emptyInfo,
		}, nil
	}
	allowAccess := apiImpl.checkAccessRoadmapNode(ctx, roadmapItem, sessItem, req.TargetMemberUserId)
	if !allowAccess {
		return &resource_exam_api.GetByRoadmapResponse{
			Code:     resource_exam_api.GetByRoadmapResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			Question: emptyInfo,
		}, nil
	}
	resourceId, valid := apiImpl.validNodeData(ctx, req.RoadmapId, req.NodeId)
	if !valid {
		return &resource_exam_api.GetByRoadmapResponse{
			Code:     resource_exam_api.GetByRoadmapResponse_CODE_NO_RESOURCE,
			ErrMsg:   "资料库不存在",
			Question: emptyInfo,
		}, nil
	}

	questionItem, err := resource_dao.QuestionInfoDao.Get(ctx, resourceId, req.QuestionId)
	if err != nil {
		return &resource_exam_api.GetByRoadmapResponse{
			Code:     resource_exam_api.GetByRoadmapResponse_CODE_NO_QUESTION,
			ErrMsg:   "问题不存在",
			Question: emptyInfo,
		}, nil
	}

	question, err := questionItem.ToQuestionInfo()
	if err != nil {
		return nil, err
	}

	stateItem, err := resource_dao.QuestionStateDao.Get(ctx, req.TargetMemberUserId, resourceId, req.QuestionId)
	if err == nil {
		answer := &anypb.Any{}
		err = proto.Unmarshal(stateItem.AnswerData, answer)
		if err != nil {
			return nil, err
		}
		question.Answer = answer
		question.AnswerTime = stateItem.AnswerTime
	} else {
		question.Answer = emptyAny
	}

	return &resource_exam_api.GetByRoadmapResponse{
		Code:     resource_exam_api.GetByRoadmapResponse_CODE_OK,
		Question: question,
	}, nil
}

func (apiImpl *ResourceExamApiImpl) SetStateByRoadmap(ctx context.Context, req *resource_exam_api.SetStateByRoadmapRequest) (*resource_exam_api.SetStateByRoadmapResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_NO_ROADMAP,
			ErrMsg: "成长路线图不存在",
		}, nil
	}
	if sessItem.UserId != roadmapItem.OwnerUserId {
		exist, err := roadmap_dao.RoadmapMemberDao.Exist(ctx, req.RoadmapId, sessItem.UserId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &resource_exam_api.SetStateByRoadmapResponse{
				Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
	}
	resourceId, valid := apiImpl.validNodeData(ctx, req.RoadmapId, req.NodeId)
	if !valid {
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_NO_RESOURCE,
			ErrMsg: "资料库不存在",
		}, nil
	}

	questionItem, err := resource_dao.QuestionInfoDao.Get(ctx, resourceId, req.QuestionId)
	if err != nil {
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_NO_QUESTION,
			ErrMsg: "问题不存在",
		}, nil
	}

	//check answer type
	question, err := questionItem.ToQuestionInfo()
	if err != nil {
		return nil, err
	}
	if question.BasicInfo.Question.MessageIs(&resource_exam_type_api.ChoiceQuestion{}) {
		if !req.Answer.MessageIs(&resource_exam_type_api.ChoiceAnswer{}) {
			return &resource_exam_api.SetStateByRoadmapResponse{
				Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_WRONG_DATA,
				ErrMsg: "错误的请求数据",
			}, nil
		}
	} else if question.BasicInfo.Question.MessageIs(&resource_exam_type_api.TrueOrFalseQuestion{}) {
		if !req.Answer.MessageIs(&resource_exam_type_api.TrueOrFalseAnswer{}) {
			return &resource_exam_api.SetStateByRoadmapResponse{
				Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_WRONG_DATA,
				ErrMsg: "错误的请求数据",
			}, nil
		}
	} else if question.BasicInfo.Question.MessageIs(&resource_exam_type_api.SimpleQuestion{}) {
		if !req.Answer.MessageIs(&resource_exam_type_api.SimpleAnswer{}) {
			return &resource_exam_api.SetStateByRoadmapResponse{
				Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_WRONG_DATA,
				ErrMsg: "错误的请求数据",
			}, nil
		}
	} else {
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code:   resource_exam_api.SetStateByRoadmapResponse_CODE_WRONG_DATA,
			ErrMsg: "错误的请求数据",
		}, nil
	}

	answerData, err := proto.Marshal(req.Answer)
	if err != nil {
		return nil, err
	}

	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx context.Context) (interface{}, error) {
		err = resource_dao.QuestionStateDao.Set(sessCtx, &resource_dao.QuestionStateItem{
			MemberUserId: sessItem.UserId,
			ResourceId:   resourceId,
			QuestionId:   req.QuestionId,
			AnswerData:   answerData,
			AnswerTime:   nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &resource_exam_api.SetStateByRoadmapResponse{
			Code: resource_exam_api.SetStateByRoadmapResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*resource_exam_api.SetStateByRoadmapResponse), nil
}

func (apiImpl *ResourceExamApiImpl) GetStateSummaryByRoadmap(ctx context.Context, req *resource_exam_api.GetStateSummaryByRoadmapRequest) (*resource_exam_api.
	GetStateSummaryByRoadmapResponse, error) {

	emptyInfo := &resource_exam_api.ExamStateSummaryInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &resource_exam_api.GetStateSummaryByRoadmapResponse{
			Code:    resource_exam_api.GetStateSummaryByRoadmapResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			Summary: emptyInfo,
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &resource_exam_api.GetStateSummaryByRoadmapResponse{
			Code:    resource_exam_api.GetStateSummaryByRoadmapResponse_CODE_NO_ROADMAP,
			ErrMsg:  "成长路线图不存在",
			Summary: emptyInfo,
		}, nil
	}
	allowAccess := apiImpl.checkAccessRoadmapNode(ctx, roadmapItem, sessItem, req.TargetMemberUserId)
	if !allowAccess {
		return &resource_exam_api.GetStateSummaryByRoadmapResponse{
			Code:    resource_exam_api.GetStateSummaryByRoadmapResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			Summary: emptyInfo,
		}, nil
	}
	resourceId, valid := apiImpl.validNodeData(ctx, req.RoadmapId, req.NodeId)
	if !valid {
		return &resource_exam_api.GetStateSummaryByRoadmapResponse{
			Code:    resource_exam_api.GetStateSummaryByRoadmapResponse_CODE_NO_RESOURCE,
			ErrMsg:  "资料库不存在",
			Summary: emptyInfo,
		}, nil
	}

	count, err := resource_dao.QuestionStateDao.Count(ctx, req.TargetMemberUserId, resourceId)
	if err != nil {
		return nil, err
	}
	return &resource_exam_api.GetStateSummaryByRoadmapResponse{
		Code: resource_exam_api.GetStateSummaryByRoadmapResponse_CODE_OK,
		Summary: &resource_exam_api.ExamStateSummaryInfo{
			AnswerCount: count,
		},
	}, nil
}
